import blue
import GameWorld
import log
import uthread
import service
import collections
import zaction
import inspect

class zactionCommonBase(service.Service):
    __guid__ = 'zaction.zactionCommonBase'

    def __init__(self, treeManager):
        self.treeManager = treeManager
        service.Service.__init__(self)



    def SetupActionTree(self, mySystemID):
        self.rootNode = GameWorld.ActionTreeNode()
        self.rootNode.ID = 0
        self.rootNode.name = 'Root'
        self.rootNode.CreateMyPropertyList()
        self.treeManager.AddTreeNode(self.rootNode)
        for treeNode in cfg.ztreeNodes:
            if (mySystemID == treeNode.systemID):
                node = GameWorld.ActionTreeNode()
                node.ID = treeNode.treeNodeID
                node.name = str(treeNode.treeNodeName)
                node.actionType = (treeNode.treeNodeType or 0)
                node.CreateMyPropertyList()
                if not self.treeManager.AddTreeNode(node):
                    log.LogError('Failed to add tree node to ActionTree', node.treeNodeName)

        for link in cfg.ztreeLinks:
            if (mySystemID == link.systemID):
                if (link.linkType is not None):
                    linkType = (link.linkType & const.zaction._ACTION_LINK_TYPE_BIT_FILTER)
                    exposureType = (link.linkType >> const.zaction._ACTION_LINK_BIT_ORDER_SPLIT)
                else:
                    linkType = 0
                    exposureType = 0
                if not self.treeManager.AddTreeLink(linkType, exposureType, link.parentTreeNodeID, link.childTreeNodeID):
                    log.LogError('Failed to add tree link to ActionTree', link.parentTreeNodeID, link.childTreeNodeID)

        import actionProcTypes
        procList = inspect.getmembers(actionProcTypes)
        for (procName, procDef,) in procList:
            if isinstance(procDef, zaction.ProcTypeDef):
                for entry in procDef.properties:
                    if isinstance(entry, zaction.ProcPropertyTypeDef):
                        GameWorld.AddActionProcNameMappingInfo(procName, entry.name, entry.isPrivate)


        for prop in cfg.ztreeNodeProperties:
            treeNode = self.treeManager.GetTreeNodeByID(prop.treeNodeID)
            if (treeNode is not None):
                if ((prop.procID is None) or (0 == prop.procID)):
                    propertyName = prop.propertyName
                else:

                    def GetMangledName(propName, procInstanceID):
                        nameLen = len(propName)
                        mangleName = ('___' + str(procInstanceID))
                        mangleNameLen = len(mangleName)
                        if ((nameLen + mangleNameLen) > const.zaction.MAX_PROP_NAME_LEN):
                            baseLen = (const.zaction.MAX_PROP_NAME_LEN - mangleNameLen)
                            propName = propName[:baseLen]
                        finalName = (propName + mangleName)
                        return finalName


                    propertyName = GetMangledName(prop.propertyName, prop.procID)
                if (False == treeNode.AddProperty(propertyName, prop.propertyBaseType, prop.propertyValue)):
                    log.LogError(((((('Failed to add ' + str(propertyName)) + ' to node ') + str(treeNode.name)) + ' ID ') + str(prop.treeNodeID)))

        for step in cfg.actionTreeSteps:
            treeNode = self.treeManager.GetTreeNodeByID(step.actionID)
            if (treeNode is not None):
                type = (step.stepType or const.zaction.ACTIONSTEP_TYPEID_NORMAL)
                loc = (step.stepLocation or const.zaction.ACTIONSTEP_LOCID_CLIENTSERVER)
                treeNode.AddActionStep(str(step.stepName), step.stepID, type, loc)

        for step in cfg.actionTreeSteps:
            treeNode = self.treeManager.GetTreeNodeByID(step.actionID)
            if (treeNode is not None):
                if (step.stepParent is not None):
                    treeNode.ConnectActionStepChildren(step.stepParent, step.stepID)
                if (step.stepSibling is not None):
                    treeNode.ConnectActionStepSiblings(step.stepSibling, step.stepID)

        for proc in cfg.actionTreeProcs:
            treeNode = self.treeManager.GetTreeNodeByID(proc.actionID)
            if (treeNode is not None):
                if ((proc.stepID is not None) and (proc.stepID != 0)):
                    stepNode = treeNode.GetActionStepByID(proc.stepID)
                    if (stepNode is None):
                        log.LogError('Failed to find step node referenced by ActionProc: ', proc.actionID, proc.stepID, proc.procType)
                    else:
                        stepNode.AddActionProcRecord(str(proc.procType), proc.procID, proc.isMaster)
                else:
                    treeNode.AddActionProcRecord(str(proc.procType), proc.procID, proc.isMaster)




    def QA_InspectSteps(self, node, depth, doChildren = True):
        while (node is not None):
            for i in xrange(depth):
                print '  ',

            print (('{' + node.name) + '}')
            if doChildren:
                child = node.GetChild()
                if (child is not None):
                    self.QA_InspectSteps(child, (depth + 1), True)
            node = node.GetNext()




    def QA_InspectTree(self, node, depth, doChildren = True):
        for i in xrange(depth):
            print '  ',

        print node.name
        self.QA_InspectSteps(node.GetStartingActionStep(), (depth + 1), True)
        if doChildren:
            children = node.GetChildren()
            for (type, child,) in children:
                self.QA_InspectTree(child, (depth + 1), (type not in const.zaction.ACTION_TREE_LINK_TYPES))




    def GetActionTree(self):
        return self.treeManager



    def ReportState(self, component):
        report = collections.OrderedDict()
        report['Current Action'] = '?'
        actionTreeNode = component.treeInstance.GetCurrentTreeNode()
        if (actionTreeNode and component.treeInstance.debugItem):
            report['Current Action'] = ('%s  duration: %f' % (actionTreeNode.name, component.treeInstance.debugItem.duration))
        return report




class zactionCommon(zactionCommonBase):
    __guid__ = 'zaction.zactionCommon'

    def __init__(self, treeManager):
        zactionCommonBase.__init__(self, treeManager)
        self.actionTickManager = GameWorld.ActionTickManager()
        self.defaultAction = 0



    @classmethod
    def GetTreeSystemID(cls):
        return const.ztree.TREE_SYSTEM_ID_DICT[const.zaction.ACTION_SCHEMA]



    def ProcessAnimationDictionary(self, animationDict):
        GameWorld.processAnimInfoYAML(animationDict)




class ProcTypeDef(object):
    __guid__ = 'zaction.ProcTypeDef'

    def __init__(self, procCategory = None, isMaster = True, isConditional = False, properties = [], displayName = None):
        self.isMaster = isMaster
        self.isConditional = isConditional
        self.properties = properties
        self.procCategory = procCategory
        self.displayName = displayName




class ProcPropertyTypeDef(object):
    __guid__ = 'zaction.ProcPropertyTypeDef'

    def __init__(self, name, dataType, userDataType = None, isPrivate = True, displayName = None, default = None, show = True):
        self.name = name
        self.dataType = dataType
        self.userDataType = userDataType
        self.isPrivate = isPrivate
        self.displayName = displayName
        self.default = default
        self.show = show




